From 6d309e1b357e06fd2a76f4eaf6ddb2390ad0eb25 Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Thu, 30 Nov 2023 05:40:13 -0700 Subject: [PATCH] make xmlgeneric a class (#1244) * make xmlgeneric a class. * encapsulate more of xmlgeneric * use scoped enum * encapsulate a bit more. * retire xg_string type * use scoped enums * rule of zero applied to xmlgeneric class. * remove test code --- gtrnctr.cc | 40 ++++---- gtrnctr.h | 141 +++++++++++++------------- kml.cc | 34 ++++--- kml.h | 45 ++++----- osm.cc | 27 ++--- osm.h | 37 +++---- xmlgeneric.cc | 156 +++++++++-------------------- xmlgeneric.h | 268 ++++++++++++++++++++++++++++---------------------- 8 files changed, 365 insertions(+), 383 deletions(-) diff --git a/gtrnctr.cc b/gtrnctr.cc index f53cccef6..5a306a79f 100644 --- a/gtrnctr.cc +++ b/gtrnctr.cc @@ -38,7 +38,7 @@ #include // for add_const<>::type #include "defs.h" // for Waypoint, route_head, computed_trkdata, waypt_add, route_disp, track_disp_all, case_ignore_strncmp, track_add_head, track_add_wpt, track_recompute, xml_parse_time, CSTR, wp_flags, WAYPT_SET, unknown_alt -#include "xmlgeneric.h" // for xg_string, build_xg_tag_map, xml_deinit, xml_init, xml_read +#include "xmlgeneric.h" // for xml_deinit, xml_init, xml_read #define MYNAME "gtc" @@ -46,19 +46,21 @@ void GtrnctrFormat::rd_init(const QString& fname) { - xml_init(fname, build_xg_tag_map(this, gtc_map), nullptr, gtc_tags_to_ignore, nullptr, true); + xml_reader = new XmlGenericReader; + xml_reader->xml_init(fname, this, gtc_map, nullptr, gtc_tags_to_ignore, nullptr); } void GtrnctrFormat::read() { - xml_read(); + xml_reader->xml_read(); } void GtrnctrFormat::rd_deinit() { - xml_deinit(); + delete xml_reader; + xml_reader = nullptr; } void @@ -359,39 +361,39 @@ GtrnctrFormat::write() } void -GtrnctrFormat::gtc_trk_s(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) +GtrnctrFormat::gtc_trk_s(const QString& /*unused*/, const QXmlStreamAttributes* /*unused*/) { trk_head = new route_head; track_add_head(trk_head); } void -GtrnctrFormat::gtc_trk_ident(xg_string args, const QXmlStreamAttributes* /*unused*/) +GtrnctrFormat::gtc_trk_ident(const QString& args, const QXmlStreamAttributes* /*unused*/) { trk_head->rte_name = args; } void -GtrnctrFormat::gtc_trk_lap_s(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) +GtrnctrFormat::gtc_trk_lap_s(const QString& /*unused*/, const QXmlStreamAttributes* /*unused*/) { lap_ct++; lap_s = 1; } void -GtrnctrFormat::gtc_trk_lap_e(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) +GtrnctrFormat::gtc_trk_lap_e(const QString& /*unused*/, const QXmlStreamAttributes* /*unused*/) { lap_s = 0; } void -GtrnctrFormat::gtc_trk_pnt_s(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) +GtrnctrFormat::gtc_trk_pnt_s(const QString& /*unused*/, const QXmlStreamAttributes* /*unused*/) { wpt_tmp = new Waypoint; } void -GtrnctrFormat::gtc_trk_pnt_e(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) +GtrnctrFormat::gtc_trk_pnt_e(const QString& /*unused*/, const QXmlStreamAttributes* /*unused*/) { if (wpt_tmp->longitude != 0. && wpt_tmp->latitude != 0.) { if (lap_s) { @@ -414,25 +416,25 @@ GtrnctrFormat::gtc_trk_pnt_e(xg_string /*unused*/, const QXmlStreamAttributes* / } void -GtrnctrFormat::gtc_trk_utc(xg_string args, const QXmlStreamAttributes* /*unused*/) +GtrnctrFormat::gtc_trk_utc(const QString& args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->creation_time = xml_parse_time(args); } void -GtrnctrFormat::gtc_trk_lat(xg_string args, const QXmlStreamAttributes* /*unused*/) +GtrnctrFormat::gtc_trk_lat(const QString& args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->latitude = args.toDouble(); } void -GtrnctrFormat::gtc_trk_long(xg_string args, const QXmlStreamAttributes* /*unused*/) +GtrnctrFormat::gtc_trk_long(const QString& args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->longitude = args.toDouble(); } void -GtrnctrFormat::gtc_trk_alt(xg_string args, const QXmlStreamAttributes* /*unused*/) +GtrnctrFormat::gtc_trk_alt(const QString& args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->altitude = args.toDouble(); } @@ -451,13 +453,13 @@ void GtrnctrFormat::gtc_trk_cad(const QString& args, const QXmlStreamAttributes* } void -GtrnctrFormat::gtc_trk_pwr(xg_string args, const QXmlStreamAttributes* /*unused*/) +GtrnctrFormat::gtc_trk_pwr(const QString& args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->power = args.toDouble(); } void -GtrnctrFormat::gtc_trk_spd(xg_string args, const QXmlStreamAttributes* /*unused*/) +GtrnctrFormat::gtc_trk_spd(const QString& args, const QXmlStreamAttributes* /*unused*/) { wpt_tmp->set_speed(args.toDouble()); } @@ -469,7 +471,7 @@ GtrnctrFormat::gtc_wpt_crs_s(const QString& /*unused*/, const QXmlStreamAttribut } void -GtrnctrFormat::gtc_wpt_crs_e(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) +GtrnctrFormat::gtc_wpt_crs_e(const QString& /*unused*/, const QXmlStreamAttributes* /*unused*/) { if (wpt_tmp->longitude != 0. && wpt_tmp->latitude != 0.) { waypt_add(wpt_tmp); @@ -481,14 +483,14 @@ GtrnctrFormat::gtc_wpt_crs_e(xg_string /*unused*/, const QXmlStreamAttributes* / } void -GtrnctrFormat::gtc_wpt_pnt_s(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) +GtrnctrFormat::gtc_wpt_pnt_s(const QString& /*unused*/, const QXmlStreamAttributes* /*unused*/) { wpt_tmp = new Waypoint; lap_ct++; } void -GtrnctrFormat::gtc_wpt_pnt_e(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) +GtrnctrFormat::gtc_wpt_pnt_e(const QString& /*unused*/, const QXmlStreamAttributes* /*unused*/) { if (wpt_tmp->longitude != 0. && wpt_tmp->latitude != 0.) { /* Add the begin position of a CourseLap as diff --git a/gtrnctr.h b/gtrnctr.h index 28a11d108..654b0d995 100644 --- a/gtrnctr.h +++ b/gtrnctr.h @@ -35,7 +35,7 @@ #include "format.h" // for Format #include "gbfile.h" // for gbfile #include "src/core/datetime.h" // for DateTime -#include "xmlgeneric.h" // for cb_cdata, xg_functor_map_entry, xg_string, cb_start, cb_end +#include "xmlgeneric.h" // for cb_cdata, xg_functor_map_entry, cb_start, cb_end class GtrnctrFormat : public Format @@ -97,25 +97,25 @@ private: void gtc_crs_hdr(const route_head* rte); void gtc_crs_ftr(const route_head* /* unused */); - void gtc_trk_s(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); - void gtc_trk_ident(xg_string args, const QXmlStreamAttributes* /* unused */); - void gtc_trk_lap_s(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); - void gtc_trk_lap_e(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); - void gtc_trk_pnt_s(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); - void gtc_trk_pnt_e(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); - void gtc_trk_utc(xg_string args, const QXmlStreamAttributes* /* unused */); - void gtc_trk_lat(xg_string args, const QXmlStreamAttributes* /* unused */); - void gtc_trk_long(xg_string args, const QXmlStreamAttributes* /* unused */); - void gtc_trk_alt(xg_string args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_s(const QString& /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_trk_ident(const QString& args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_lap_s(const QString& /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_trk_lap_e(const QString& /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_trk_pnt_s(const QString& /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_trk_pnt_e(const QString& /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_trk_utc(const QString& args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_lat(const QString& args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_long(const QString& args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_alt(const QString& args, const QXmlStreamAttributes* /* unused */); void gtc_trk_dist(const QString& args, const QXmlStreamAttributes* /* unused */); void gtc_trk_hr(const QString& args, const QXmlStreamAttributes* /* unused */); void gtc_trk_cad(const QString& args, const QXmlStreamAttributes* /* unused */); - void gtc_trk_pwr(xg_string args, const QXmlStreamAttributes* /* unused */); - void gtc_trk_spd(xg_string args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_pwr(const QString& args, const QXmlStreamAttributes* /* unused */); + void gtc_trk_spd(const QString& args, const QXmlStreamAttributes* /* unused */); void gtc_wpt_crs_s(const QString& /* unused */, const QXmlStreamAttributes* /* unused */); - void gtc_wpt_crs_e(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); - void gtc_wpt_pnt_s(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); - void gtc_wpt_pnt_e(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_wpt_crs_e(const QString& /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_wpt_pnt_s(const QString& /* unused */, const QXmlStreamAttributes* /* unused */); + void gtc_wpt_pnt_e(const QString& /* unused */, const QXmlStreamAttributes* /* unused */); void gtc_wpt_ident(const QString& args, const QXmlStreamAttributes* /* unused */); void gtc_wpt_lat(const QString& args, const QXmlStreamAttributes* /* unused */); void gtc_wpt_long(const QString& args, const QXmlStreamAttributes* /* unused */); @@ -154,71 +154,72 @@ private: }, }; - QList> gtc_map = { + QList> gtc_map = { /* courses tcx v1 & v2 */ - { &GtrnctrFormat::gtc_trk_s, cb_start, "/Courses/Course" }, - { &GtrnctrFormat::gtc_trk_ident,cb_cdata, "/Courses/Course/Name"}, - { &GtrnctrFormat::gtc_trk_pnt_s,cb_start, "/Courses/Course/Track/Trackpoint" }, - { &GtrnctrFormat::gtc_trk_pnt_e,cb_end, "/Courses/Course/Track/Trackpoint" }, - { &GtrnctrFormat::gtc_trk_utc, cb_cdata, "/Courses/Course/Track/Trackpoint/Time" }, - { &GtrnctrFormat::gtc_trk_lat, cb_cdata, "/Courses/Course/Track/Trackpoint/Position/LatitudeDegrees" }, - { &GtrnctrFormat::gtc_trk_long, cb_cdata, "/Courses/Course/Track/Trackpoint/Position/LongitudeDegrees" }, - { &GtrnctrFormat::gtc_trk_alt, cb_cdata, "/Courses/Course/Track/Trackpoint/AltitudeMeters" }, - { &GtrnctrFormat::gtc_trk_hr, cb_cdata, "/Courses/Course/Track/Trackpoint/HeartRateBpm" }, - { &GtrnctrFormat::gtc_trk_cad, cb_cdata, "/Courses/Course/Track/Trackpoint/Cadence" }, - { &GtrnctrFormat::gtc_wpt_crs_s,cb_start, "/Courses/Course/CoursePoint" }, - { &GtrnctrFormat::gtc_wpt_crs_e,cb_end, "/Courses/Course/CoursePoint" }, - { &GtrnctrFormat::gtc_wpt_ident,cb_cdata, "/Courses/Course/CoursePoint/Name"}, - { &GtrnctrFormat::gtc_trk_utc, cb_cdata, "/Courses/Course/CoursePoint/Time"}, - { &GtrnctrFormat::gtc_wpt_lat, cb_cdata, "/Courses/Course/CoursePoint/Position/LatitudeDegrees"}, - { &GtrnctrFormat::gtc_wpt_long, cb_cdata, "/Courses/Course/CoursePoint/Position/LongitudeDegrees"}, - { &GtrnctrFormat::gtc_trk_alt, cb_cdata, "/Courses/Course/CoursePoint/AltitudeMeters" }, - { &GtrnctrFormat::gtc_wpt_icon, cb_cdata, "/Courses/Course/CoursePoint/PointType" }, - { &GtrnctrFormat::gtc_wpt_notes,cb_cdata, "/Courses/Course/CoursePoint/Notes" }, + { &GtrnctrFormat::gtc_trk_s, xg_cb_type::cb_start, "/Courses/Course" }, + { &GtrnctrFormat::gtc_trk_ident, xg_cb_type::cb_cdata, "/Courses/Course/Name"}, + { &GtrnctrFormat::gtc_trk_pnt_s, xg_cb_type::cb_start, "/Courses/Course/Track/Trackpoint" }, + { &GtrnctrFormat::gtc_trk_pnt_e, xg_cb_type::cb_end, "/Courses/Course/Track/Trackpoint" }, + { &GtrnctrFormat::gtc_trk_utc, xg_cb_type::cb_cdata, "/Courses/Course/Track/Trackpoint/Time" }, + { &GtrnctrFormat::gtc_trk_lat, xg_cb_type::cb_cdata, "/Courses/Course/Track/Trackpoint/Position/LatitudeDegrees" }, + { &GtrnctrFormat::gtc_trk_long, xg_cb_type::cb_cdata, "/Courses/Course/Track/Trackpoint/Position/LongitudeDegrees" }, + { &GtrnctrFormat::gtc_trk_alt, xg_cb_type::cb_cdata, "/Courses/Course/Track/Trackpoint/AltitudeMeters" }, + { &GtrnctrFormat::gtc_trk_hr, xg_cb_type::cb_cdata, "/Courses/Course/Track/Trackpoint/HeartRateBpm" }, + { &GtrnctrFormat::gtc_trk_cad, xg_cb_type::cb_cdata, "/Courses/Course/Track/Trackpoint/Cadence" }, + { &GtrnctrFormat::gtc_wpt_crs_s, xg_cb_type::cb_start, "/Courses/Course/CoursePoint" }, + { &GtrnctrFormat::gtc_wpt_crs_e, xg_cb_type::cb_end, "/Courses/Course/CoursePoint" }, + { &GtrnctrFormat::gtc_wpt_ident, xg_cb_type::cb_cdata, "/Courses/Course/CoursePoint/Name"}, + { &GtrnctrFormat::gtc_trk_utc, xg_cb_type::cb_cdata, "/Courses/Course/CoursePoint/Time"}, + { &GtrnctrFormat::gtc_wpt_lat, xg_cb_type::cb_cdata, "/Courses/Course/CoursePoint/Position/LatitudeDegrees"}, + { &GtrnctrFormat::gtc_wpt_long, xg_cb_type::cb_cdata, "/Courses/Course/CoursePoint/Position/LongitudeDegrees"}, + { &GtrnctrFormat::gtc_trk_alt, xg_cb_type::cb_cdata, "/Courses/Course/CoursePoint/AltitudeMeters" }, + { &GtrnctrFormat::gtc_wpt_icon, xg_cb_type::cb_cdata, "/Courses/Course/CoursePoint/PointType" }, + { &GtrnctrFormat::gtc_wpt_notes, xg_cb_type::cb_cdata, "/Courses/Course/CoursePoint/Notes" }, /* history tcx v2 (activities) */ - { &GtrnctrFormat::gtc_trk_s, cb_start, "/Activities/Activity" }, - { &GtrnctrFormat::gtc_trk_ident,cb_cdata, "/Activities/Activity/Id" }, - { &GtrnctrFormat::gtc_trk_lap_s,cb_start, "/Activities/Activity/Lap" }, - { &GtrnctrFormat::gtc_trk_lap_e,cb_end, "/Activities/Activity/Lap" }, - { &GtrnctrFormat::gtc_trk_pnt_s,cb_start, "/Activities/Activity/Lap/Track/Trackpoint" }, - { &GtrnctrFormat::gtc_trk_pnt_e,cb_end, "/Activities/Activity/Lap/Track/Trackpoint" }, - { &GtrnctrFormat::gtc_trk_utc, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Time" }, - { &GtrnctrFormat::gtc_trk_lat, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Position/LatitudeDegrees" }, - { &GtrnctrFormat::gtc_trk_long, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Position/LongitudeDegrees" }, - { &GtrnctrFormat::gtc_trk_alt, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/AltitudeMeters" }, - { &GtrnctrFormat::gtc_trk_dist, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/DistanceMeters" }, - { &GtrnctrFormat::gtc_trk_hr, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/HeartRateBpm" }, - { &GtrnctrFormat::gtc_trk_cad, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Cadence" }, - { &GtrnctrFormat::gtc_trk_pwr, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Extensions/ns3:TPX/ns3:Watts" }, + { &GtrnctrFormat::gtc_trk_s, xg_cb_type::cb_start, "/Activities/Activity" }, + { &GtrnctrFormat::gtc_trk_ident, xg_cb_type::cb_cdata, "/Activities/Activity/Id" }, + { &GtrnctrFormat::gtc_trk_lap_s, xg_cb_type::cb_start, "/Activities/Activity/Lap" }, + { &GtrnctrFormat::gtc_trk_lap_e, xg_cb_type::cb_end, "/Activities/Activity/Lap" }, + { &GtrnctrFormat::gtc_trk_pnt_s, xg_cb_type::cb_start, "/Activities/Activity/Lap/Track/Trackpoint" }, + { &GtrnctrFormat::gtc_trk_pnt_e, xg_cb_type::cb_end, "/Activities/Activity/Lap/Track/Trackpoint" }, + { &GtrnctrFormat::gtc_trk_utc, xg_cb_type::cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Time" }, + { &GtrnctrFormat::gtc_trk_lat, xg_cb_type::cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Position/LatitudeDegrees" }, + { &GtrnctrFormat::gtc_trk_long, xg_cb_type::cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Position/LongitudeDegrees" }, + { &GtrnctrFormat::gtc_trk_alt, xg_cb_type::cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/AltitudeMeters" }, + { &GtrnctrFormat::gtc_trk_dist, xg_cb_type::cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/DistanceMeters" }, + { &GtrnctrFormat::gtc_trk_hr, xg_cb_type::cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/HeartRateBpm" }, + { &GtrnctrFormat::gtc_trk_cad, xg_cb_type::cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Cadence" }, + { &GtrnctrFormat::gtc_trk_pwr, xg_cb_type::cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Extensions/ns3:TPX/ns3:Watts" }, // Sample from Marcelo Kittlein 5/2014 declares a default namespace with the start tag of the TPX element, // and thus doesn't use prefixes. - { &GtrnctrFormat::gtc_trk_pwr, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Extensions/TPX/Watts" }, + { &GtrnctrFormat::gtc_trk_pwr, xg_cb_type::cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Extensions/TPX/Watts" }, // It looks like Speed and Watts should be siblings, but Garmin can't get // their namespace act very consistent. This works for a sample provided // by Laurent Desmons in 5/2013. - { &GtrnctrFormat::gtc_trk_spd, cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Extensions/TPX/Speed" }, + { &GtrnctrFormat::gtc_trk_spd, xg_cb_type::cb_cdata, "/Activities/Activity/Lap/Track/Trackpoint/Extensions/TPX/Speed" }, /* history tcx v1 */ - { &GtrnctrFormat::gtc_trk_s, cb_start, "/History/Run" }, - { &GtrnctrFormat::gtc_trk_ident,cb_cdata, "/History/Run/Id" }, - { &GtrnctrFormat::gtc_trk_lap_s,cb_start, "/History/Run/Lap" }, - { &GtrnctrFormat::gtc_trk_lap_e,cb_end, "/History/Run/Lap" }, - { &GtrnctrFormat::gtc_trk_pnt_s,cb_start, "/History/Run/Lap/Track/Trackpoint" }, - { &GtrnctrFormat::gtc_trk_pnt_e,cb_end, "/History/Run/Lap/Track/Trackpoint" }, - { &GtrnctrFormat::gtc_trk_utc, cb_cdata, "/History/Run/Lap/Track/Trackpoint/Time" }, - { &GtrnctrFormat::gtc_trk_lat, cb_cdata, "/History/Run/Lap/Track/Trackpoint/Position/LatitudeDegrees" }, - { &GtrnctrFormat::gtc_trk_long, cb_cdata, "/History/Run/Lap/Track/Trackpoint/Position/LongitudeDegrees" }, - { &GtrnctrFormat::gtc_trk_alt, cb_cdata, "/History/Run/Lap/Track/Trackpoint/AltitudeMeters" }, - { &GtrnctrFormat::gtc_trk_hr, cb_cdata, "/History/Run/Lap/Track/Trackpoint/HeartRateBpm" }, - { &GtrnctrFormat::gtc_trk_cad, cb_cdata, "/History/Run/Lap/Track/Trackpoint/Cadence" }, - - { &GtrnctrFormat::gtc_wpt_pnt_s,cb_start, "/Courses/Course/Lap/BeginPosition" }, - { &GtrnctrFormat::gtc_wpt_pnt_e,cb_end, "/Courses/Course/Lap/BeginPosition" }, - { &GtrnctrFormat::gtc_wpt_lat, cb_cdata, "/Courses/Course/Lap/BeginPosition/LatitudeDegrees" }, - { &GtrnctrFormat::gtc_wpt_long, cb_cdata, "/Courses/Course/Lap/BeginPosition/LongitudeDegrees" }, - { &GtrnctrFormat::gtc_trk_alt, cb_cdata, "/Courses/Course/Lap/BeginAltitudeMeters" } + { &GtrnctrFormat::gtc_trk_s, xg_cb_type::cb_start, "/History/Run" }, + { &GtrnctrFormat::gtc_trk_ident, xg_cb_type::cb_cdata, "/History/Run/Id" }, + { &GtrnctrFormat::gtc_trk_lap_s, xg_cb_type::cb_start, "/History/Run/Lap" }, + { &GtrnctrFormat::gtc_trk_lap_e, xg_cb_type::cb_end, "/History/Run/Lap" }, + { &GtrnctrFormat::gtc_trk_pnt_s, xg_cb_type::cb_start, "/History/Run/Lap/Track/Trackpoint" }, + { &GtrnctrFormat::gtc_trk_pnt_e, xg_cb_type::cb_end, "/History/Run/Lap/Track/Trackpoint" }, + { &GtrnctrFormat::gtc_trk_utc, xg_cb_type::cb_cdata, "/History/Run/Lap/Track/Trackpoint/Time" }, + { &GtrnctrFormat::gtc_trk_lat, xg_cb_type::cb_cdata, "/History/Run/Lap/Track/Trackpoint/Position/LatitudeDegrees" }, + { &GtrnctrFormat::gtc_trk_long, xg_cb_type::cb_cdata, "/History/Run/Lap/Track/Trackpoint/Position/LongitudeDegrees" }, + { &GtrnctrFormat::gtc_trk_alt, xg_cb_type::cb_cdata, "/History/Run/Lap/Track/Trackpoint/AltitudeMeters" }, + { &GtrnctrFormat::gtc_trk_hr, xg_cb_type::cb_cdata, "/History/Run/Lap/Track/Trackpoint/HeartRateBpm" }, + { &GtrnctrFormat::gtc_trk_cad, xg_cb_type::cb_cdata, "/History/Run/Lap/Track/Trackpoint/Cadence" }, + + { &GtrnctrFormat::gtc_wpt_pnt_s, xg_cb_type::cb_start, "/Courses/Course/Lap/BeginPosition" }, + { &GtrnctrFormat::gtc_wpt_pnt_e, xg_cb_type::cb_end, "/Courses/Course/Lap/BeginPosition" }, + { &GtrnctrFormat::gtc_wpt_lat, xg_cb_type::cb_cdata, "/Courses/Course/Lap/BeginPosition/LatitudeDegrees" }, + { &GtrnctrFormat::gtc_wpt_long, xg_cb_type::cb_cdata, "/Courses/Course/Lap/BeginPosition/LongitudeDegrees" }, + { &GtrnctrFormat::gtc_trk_alt, xg_cb_type::cb_cdata, "/Courses/Course/Lap/BeginAltitudeMeters" } }; + XmlGenericReader* xml_reader{nullptr}; int gtc_indent_level{}; }; diff --git a/kml.cc b/kml.cc index 8e59b3eca..d7e9c826b 100644 --- a/kml.cc +++ b/kml.cc @@ -57,7 +57,7 @@ #include "src/core/xmlstreamwriter.h" // for XmlStreamWriter #include "src/core/xmltag.h" // for xml_findfirst, xml_tag, fs_xml, xml_attribute, xml_findnext #include "units.h" // for UnitsFormatter, UnitsFormatter... -#include "xmlgeneric.h" // for cb_cdata, cb_end, cb_start, xg_callback, xg_string, xg_cb_type, xml_deinit, xml_ignore_tags, xml_init, xml_read, xg_tag_mapping +#include "xmlgeneric.h" // for cb_cdata, cb_end, cb_start, xg_callback, xg_cb_type, xml_deinit, xml_ignore_tags, xml_init, xml_read, xg_tag_mapping // Icons provided and hosted by Google. Used with permission. @@ -134,7 +134,7 @@ void KmlFormat::kml_step_color() kml_color_sequencer.seq += kml_color_sequencer.step; } -void KmlFormat::wpt_s(xg_string /*args*/, const QXmlStreamAttributes* /*attrs*/) +void KmlFormat::wpt_s(const QString& /*args*/, const QXmlStreamAttributes* /*attrs*/) { if (wpt_tmp) { fatal(MYNAME ": wpt_s: invalid kml file\n"); @@ -148,7 +148,7 @@ void KmlFormat::wpt_s(xg_string /*args*/, const QXmlStreamAttributes* /*attrs*/) wpt_timespan_end = gpsbabel::DateTime(); } -void KmlFormat::wpt_e(xg_string /*args*/, const QXmlStreamAttributes* /*attrs*/) +void KmlFormat::wpt_e(const QString& /*args*/, const QXmlStreamAttributes* /*attrs*/) { if (!wpt_tmp) { fatal(MYNAME ": wpt_e: invalid kml file\n"); @@ -163,7 +163,7 @@ void KmlFormat::wpt_e(xg_string /*args*/, const QXmlStreamAttributes* /*attrs*/) wpt_tmp_queued = false; } -void KmlFormat::wpt_name(xg_string args, const QXmlStreamAttributes* /*attrs*/) +void KmlFormat::wpt_name(const QString& args, const QXmlStreamAttributes* /*attrs*/) { if (!wpt_tmp) { fatal(MYNAME ": wpt_name: invalid kml file\n"); @@ -179,7 +179,7 @@ void KmlFormat::wpt_desc(const QString& args, const QXmlStreamAttributes* /*attr wpt_tmp->description += args.trimmed(); } -void KmlFormat::wpt_time(xg_string args, const QXmlStreamAttributes* /*attrs*/) +void KmlFormat::wpt_time(const QString& args, const QXmlStreamAttributes* /*attrs*/) { if (!wpt_tmp) { fatal(MYNAME ": wpt_time: invalid kml file\n"); @@ -187,12 +187,12 @@ void KmlFormat::wpt_time(xg_string args, const QXmlStreamAttributes* /*attrs*/) wpt_tmp->SetCreationTime(xml_parse_time(args)); } -void KmlFormat::wpt_ts_begin(xg_string args, const QXmlStreamAttributes* /*attrs*/) +void KmlFormat::wpt_ts_begin(const QString& args, const QXmlStreamAttributes* /*attrs*/) { wpt_timespan_begin = xml_parse_time(args); } -void KmlFormat::wpt_ts_end(xg_string args, const QXmlStreamAttributes* /*attrs*/) +void KmlFormat::wpt_ts_end(const QString& args, const QXmlStreamAttributes* /*attrs*/) { wpt_timespan_end = xml_parse_time(args); } @@ -215,14 +215,14 @@ void KmlFormat::wpt_coord(const QString& args, const QXmlStreamAttributes* /*att wpt_tmp_queued = true; } -void KmlFormat::wpt_icon(xg_string args, const QXmlStreamAttributes* /*attrs*/) +void KmlFormat::wpt_icon(const QString& args, const QXmlStreamAttributes* /*attrs*/) { if (wpt_tmp) { wpt_tmp->icon_descr = args; } } -void KmlFormat::trk_coord(xg_string args, const QXmlStreamAttributes* /*attrs*/) +void KmlFormat::trk_coord(const QString& args, const QXmlStreamAttributes* /*attrs*/) { auto* trk_head = new route_head; if (wpt_tmp && !wpt_tmp->shortname.isEmpty()) { @@ -274,7 +274,7 @@ void KmlFormat::trk_coord(xg_string args, const QXmlStreamAttributes* /*attrs*/) } } -void KmlFormat::gx_trk_s(xg_string /*args*/, const QXmlStreamAttributes* /*attrs*/) +void KmlFormat::gx_trk_s(const QString& /*args*/, const QXmlStreamAttributes* /*attrs*/) { gx_trk_head = new route_head; if (wpt_tmp && !wpt_tmp->shortname.isEmpty()) { @@ -290,7 +290,7 @@ void KmlFormat::gx_trk_s(xg_string /*args*/, const QXmlStreamAttributes* /*attrs gx_trk_coords = new QList>; } -void KmlFormat::gx_trk_e(xg_string /*args*/, const QXmlStreamAttributes* /*attrs*/) +void KmlFormat::gx_trk_e(const QString& /*args*/, const QXmlStreamAttributes* /*attrs*/) { // Check that for every temporal value (kml:when) in a kml:Track there is a position (kml:coord) value. // Check that for every temporal value (kml:when) in a gx:Track there is a position (gx:coord) value. @@ -331,7 +331,7 @@ void KmlFormat::gx_trk_e(xg_string /*args*/, const QXmlStreamAttributes* /*attrs gx_trk_coords = nullptr; } -void KmlFormat::gx_trk_when(xg_string args, const QXmlStreamAttributes* /*attrs*/) +void KmlFormat::gx_trk_when(const QString& args, const QXmlStreamAttributes* /*attrs*/) { if (! gx_trk_times) { fatal(MYNAME ": gx_trk_when: invalid kml file\n"); @@ -339,7 +339,7 @@ void KmlFormat::gx_trk_when(xg_string args, const QXmlStreamAttributes* /*attrs* gx_trk_times->append(xml_parse_time(args)); } -void KmlFormat::gx_trk_coord(xg_string args, const QXmlStreamAttributes* /*attrs*/) +void KmlFormat::gx_trk_coord(const QString& args, const QXmlStreamAttributes* /*attrs*/) { if (! gx_trk_coords) { fatal(MYNAME ": gx_trk_coord: invalid kml file\n"); @@ -355,17 +355,19 @@ void KmlFormat::gx_trk_coord(xg_string args, const QXmlStreamAttributes* /*attrs void KmlFormat::rd_init(const QString& fname) { - xml_init(fname, build_xg_tag_map(this, kml_map), nullptr, kml_tags_to_ignore, kml_tags_to_skip, true); + xml_reader = new XmlGenericReader; + xml_reader->xml_init(fname, this, kml_map, nullptr, kml_tags_to_ignore, kml_tags_to_skip); } void KmlFormat::read() { - xml_read(); + xml_reader->xml_read(); } void KmlFormat::rd_deinit() { - xml_deinit(); + delete xml_reader; + xml_reader = nullptr; } void KmlFormat::wr_init(const QString& fname) diff --git a/kml.h b/kml.h index 64b7f1f72..eef489c57 100644 --- a/kml.h +++ b/kml.h @@ -37,7 +37,7 @@ #include "src/core/file.h" // for File #include "src/core/xmlstreamwriter.h" // for XmlStreamWriter #include "units.h" // for UnitsFormatter -#include "xmlgeneric.h" // for cb_cdata, cb_end, cb_start, xg_callback, xg_string, xg_cb_type, xml_deinit, xml_ignore_tags, xml_init, xml_read, xg_tag_mapping +#include "xmlgeneric.h" // for cb_cdata, cb_end, cb_start, xg_callback, xg_cb_type, xml_deinit, xml_ignore_tags, xml_init, xml_read, xg_tag_mapping class KmlFormat : public Format @@ -331,29 +331,30 @@ private: gb_color color; } kml_color_sequencer; - QList> kml_map = { - {&KmlFormat::wpt_s, cb_start, "/Placemark"}, - {&KmlFormat::wpt_e, cb_end, "/Placemark"}, - {&KmlFormat::wpt_name, cb_cdata, "/Placemark/name"}, - {&KmlFormat::wpt_desc, cb_cdata, "/Placemark/description"}, - {&KmlFormat::wpt_ts_begin, cb_cdata,"/Placemark/TimeSpan/begin"}, - {&KmlFormat::wpt_ts_end, cb_cdata, "/Placemark/TimeSpan/end"}, - {&KmlFormat::wpt_time, cb_cdata, "/Placemark/TimeStamp/when"}, + QList> kml_map = { + {&KmlFormat::wpt_s, xg_cb_type::cb_start, "/Placemark"}, + {&KmlFormat::wpt_e, xg_cb_type::cb_end, "/Placemark"}, + {&KmlFormat::wpt_name, xg_cb_type::cb_cdata, "/Placemark/name"}, + {&KmlFormat::wpt_desc, xg_cb_type::cb_cdata, "/Placemark/description"}, + {&KmlFormat::wpt_ts_begin, xg_cb_type::cb_cdata,"/Placemark/TimeSpan/begin"}, + {&KmlFormat::wpt_ts_end, xg_cb_type::cb_cdata, "/Placemark/TimeSpan/end"}, + {&KmlFormat::wpt_time, xg_cb_type::cb_cdata, "/Placemark/TimeStamp/when"}, // Alias for above used in KML 2.0 - {&KmlFormat::wpt_time, cb_cdata, "/Placemark/TimeInstant/timePosition"}, - {&KmlFormat::wpt_coord, cb_cdata, "/Placemark/(.+/)?Point/coordinates"}, - {&KmlFormat::wpt_icon, cb_cdata, "/Placemark/Style/Icon/href"}, - {&KmlFormat::trk_coord, cb_cdata, "/Placemark/(.+/)?LineString/coordinates"}, - {&KmlFormat::trk_coord, cb_cdata, "/Placemark/(.+)/?LinearRing/coordinates"}, - {&KmlFormat::gx_trk_s, cb_start, "/Placemark/(.+/)?gx:Track"}, - {&KmlFormat::gx_trk_e, cb_end, "/Placemark/(.+/)?gx:Track"}, - {&KmlFormat::gx_trk_when, cb_cdata, "/Placemark/(.+/)?gx:Track/when"}, - {&KmlFormat::gx_trk_coord, cb_cdata, "/Placemark/(.+/)?gx:Track/gx:coord"}, - {&KmlFormat::gx_trk_s, cb_start, "/Placemark/(.+/)?Track"}, // KML 2.3 - {&KmlFormat::gx_trk_e, cb_end, "/Placemark/(.+/)?Track"}, // KML 2.3 - {&KmlFormat::gx_trk_when, cb_cdata, "/Placemark/(.+/)?Track/when"}, // KML 2.3 - {&KmlFormat::gx_trk_coord, cb_cdata, "/Placemark/(.+/)?Track/coord"}, // KML 2.3 + {&KmlFormat::wpt_time, xg_cb_type::cb_cdata, "/Placemark/TimeInstant/timePosition"}, + {&KmlFormat::wpt_coord, xg_cb_type::cb_cdata, "/Placemark/(.+/)?Point/coordinates"}, + {&KmlFormat::wpt_icon, xg_cb_type::cb_cdata, "/Placemark/Style/Icon/href"}, + {&KmlFormat::trk_coord, xg_cb_type::cb_cdata, "/Placemark/(.+/)?LineString/coordinates"}, + {&KmlFormat::trk_coord, xg_cb_type::cb_cdata, "/Placemark/(.+)/?LinearRing/coordinates"}, + {&KmlFormat::gx_trk_s, xg_cb_type::cb_start, "/Placemark/(.+/)?gx:Track"}, + {&KmlFormat::gx_trk_e, xg_cb_type::cb_end, "/Placemark/(.+/)?gx:Track"}, + {&KmlFormat::gx_trk_when, xg_cb_type::cb_cdata, "/Placemark/(.+/)?gx:Track/when"}, + {&KmlFormat::gx_trk_coord, xg_cb_type::cb_cdata, "/Placemark/(.+/)?gx:Track/gx:coord"}, + {&KmlFormat::gx_trk_s, xg_cb_type::cb_start, "/Placemark/(.+/)?Track"}, // KML 2.3 + {&KmlFormat::gx_trk_e, xg_cb_type::cb_end, "/Placemark/(.+/)?Track"}, // KML 2.3 + {&KmlFormat::gx_trk_when, xg_cb_type::cb_cdata, "/Placemark/(.+/)?Track/when"}, // KML 2.3 + {&KmlFormat::gx_trk_coord, xg_cb_type::cb_cdata, "/Placemark/(.+/)?Track/coord"}, // KML 2.3 }; + XmlGenericReader* xml_reader{nullptr}; // The TimeSpan/begin and TimeSpan/end DateTimes: gpsbabel::DateTime wpt_timespan_begin, wpt_timespan_end; diff --git a/osm.cc b/osm.cc index 1409cc831..298f0b07c 100644 --- a/osm.cc +++ b/osm.cc @@ -34,7 +34,7 @@ #include "osm.h" #include "src/core/datetime.h" // for DateTime #include "src/core/xmlstreamwriter.h" // for XmlStreamWriter -#include "xmlgeneric.h" // for xg_string, build_xg_tag_map, xml_deinit, xml_init, xml_read +#include "xmlgeneric.h" // for xml_deinit, xml_init, xml_read #define MYNAME "osm" @@ -413,7 +413,7 @@ OsmFormat::osm_strip_html(const QString& str) } void -OsmFormat::osm_node_end(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) +OsmFormat::osm_node_end(const QString& /*unused*/, const QXmlStreamAttributes* /*unused*/) { if (wpt) { if (wpt->wpt_flags.fmt_use) { @@ -426,7 +426,7 @@ OsmFormat::osm_node_end(xg_string /*unused*/, const QXmlStreamAttributes* /*unus } void -OsmFormat::osm_node(xg_string /*unused*/, const QXmlStreamAttributes* attrv) +OsmFormat::osm_node(const QString& /*unused*/, const QXmlStreamAttributes* attrv) { wpt = new Waypoint; @@ -457,7 +457,7 @@ OsmFormat::osm_node(xg_string /*unused*/, const QXmlStreamAttributes* attrv) } void -OsmFormat::osm_node_tag(xg_string /*unused*/, const QXmlStreamAttributes* attrv) +OsmFormat::osm_node_tag(const QString& /*unused*/, const QXmlStreamAttributes* attrv) { QString key, value; signed char ikey; @@ -510,7 +510,7 @@ OsmFormat::osm_node_tag(xg_string /*unused*/, const QXmlStreamAttributes* attrv) } void -OsmFormat::osm_way(xg_string /*unused*/, const QXmlStreamAttributes* attrv) +OsmFormat::osm_way(const QString& /*unused*/, const QXmlStreamAttributes* attrv) { rte = new route_head; // create a wpt to represent the route center if it has a center tag @@ -521,7 +521,7 @@ OsmFormat::osm_way(xg_string /*unused*/, const QXmlStreamAttributes* attrv) } void -OsmFormat::osm_way_nd(xg_string /*unused*/, const QXmlStreamAttributes* attrv) +OsmFormat::osm_way_nd(const QString& /*unused*/, const QXmlStreamAttributes* attrv) { if (attrv->hasAttribute("ref")) { QString atstr = attrv->value("ref").toString(); @@ -537,7 +537,7 @@ OsmFormat::osm_way_nd(xg_string /*unused*/, const QXmlStreamAttributes* attrv) } void -OsmFormat::osm_way_tag(xg_string /*unused*/, const QXmlStreamAttributes* attrv) +OsmFormat::osm_way_tag(const QString& /*unused*/, const QXmlStreamAttributes* attrv) { QString key, value; signed char ikey; @@ -574,7 +574,7 @@ OsmFormat::osm_way_tag(xg_string /*unused*/, const QXmlStreamAttributes* attrv) } void -OsmFormat::osm_way_center(xg_string /*unused*/, const QXmlStreamAttributes* attrv) +OsmFormat::osm_way_center(const QString& /*unused*/, const QXmlStreamAttributes* attrv) { wpt->wpt_flags.fmt_use = 1; @@ -587,7 +587,7 @@ OsmFormat::osm_way_center(xg_string /*unused*/, const QXmlStreamAttributes* attr } void -OsmFormat::osm_way_end(xg_string /*unused*/, const QXmlStreamAttributes* /*unused*/) +OsmFormat::osm_way_end(const QString& /*unused*/, const QXmlStreamAttributes* /*unused*/) { if (rte) { route_add_head(rte); @@ -615,19 +615,22 @@ OsmFormat::rd_init(const QString& fname) osm_features_init(); } - xml_init(fname, build_xg_tag_map(this, osm_map), nullptr, nullptr, nullptr, true); + xml_reader = new XmlGenericReader; + xml_reader->xml_init(fname, this, osm_map); } void OsmFormat::read() { - xml_read(); + xml_reader->xml_read(); } void OsmFormat::rd_deinit() { - xml_deinit(); + delete xml_reader; + xml_reader = nullptr; + waypoints.clear(); } diff --git a/osm.h b/osm.h index 87590b45b..4a07c2350 100644 --- a/osm.h +++ b/osm.h @@ -33,7 +33,7 @@ #include "format.h" // for Format #include "src/core/file.h" // for File #include "src/core/xmlstreamwriter.h" // for XmlStreamWriter -#include "xmlgeneric.h" // for xg_functor_map_entry, cb_start, cb_end, xg_string +#include "xmlgeneric.h" // for xg_functor_map_entry, cb_start, cb_end class OsmFormat : public Format @@ -88,14 +88,14 @@ private: char osm_feature_ikey(const QString& key) const; QString osm_feature_symbol(int ikey, const char* value) const; static QString osm_strip_html(const QString& str); - void osm_node_end(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); - void osm_node(xg_string /* unused */, const QXmlStreamAttributes* attrv); - void osm_node_tag(xg_string /* unused */, const QXmlStreamAttributes* attrv); - void osm_way(xg_string /* unused */, const QXmlStreamAttributes* attrv); - void osm_way_nd(xg_string /* unused */, const QXmlStreamAttributes* attrv); - void osm_way_tag(xg_string /* unused */, const QXmlStreamAttributes* attrv); - void osm_way_center(xg_string /* unused */, const QXmlStreamAttributes* attrv); - void osm_way_end(xg_string /* unused */, const QXmlStreamAttributes* /* unused */); + void osm_node_end(const QString& /* unused */, const QXmlStreamAttributes* /* unused */); + void osm_node(const QString& /* unused */, const QXmlStreamAttributes* attrv); + void osm_node_tag(const QString& /* unused */, const QXmlStreamAttributes* attrv); + void osm_way(const QString& /* unused */, const QXmlStreamAttributes* attrv); + void osm_way_nd(const QString& /* unused */, const QXmlStreamAttributes* attrv); + void osm_way_tag(const QString& /* unused */, const QXmlStreamAttributes* attrv); + void osm_way_center(const QString& /* unused */, const QXmlStreamAttributes* attrv); + void osm_way_end(const QString& /* unused */, const QXmlStreamAttributes* /* unused */); void osm_init_icons(); void osm_write_tag(const QString& key, const QString& value) const; void osm_disp_feature(const Waypoint* waypoint) const; @@ -133,15 +133,16 @@ private: route_head* rte{}; Waypoint* wpt{}; - QList> osm_map = { - {&OsmFormat::osm_node, cb_start, "/osm/node"}, - {&OsmFormat::osm_node_tag, cb_start, "/osm/node/tag"}, - {&OsmFormat::osm_node_end, cb_end, "/osm/node"}, - {&OsmFormat::osm_way, cb_start, "/osm/way"}, - {&OsmFormat::osm_way_nd, cb_start, "/osm/way/nd"}, - {&OsmFormat::osm_way_tag, cb_start, "/osm/way/tag"}, - {&OsmFormat::osm_way_center, cb_start, "/osm/way/center"}, - {&OsmFormat::osm_way_end, cb_end, "/osm/way"} + QList> osm_map { + {&OsmFormat::osm_node, xg_cb_type::cb_start, "/osm/node"}, + {&OsmFormat::osm_node_tag, xg_cb_type::cb_start, "/osm/node/tag"}, + {&OsmFormat::osm_node_end, xg_cb_type::cb_end, "/osm/node"}, + {&OsmFormat::osm_way, xg_cb_type::cb_start, "/osm/way"}, + {&OsmFormat::osm_way_nd, xg_cb_type::cb_start, "/osm/way/nd"}, + {&OsmFormat::osm_way_tag, xg_cb_type::cb_start, "/osm/way/tag"}, + {&OsmFormat::osm_way_center, xg_cb_type::cb_start, "/osm/way/center"}, + {&OsmFormat::osm_way_end, xg_cb_type::cb_end, "/osm/way"} }; + XmlGenericReader* xml_reader{nullptr}; }; #endif // OSM_H_INCLUDED_ diff --git a/xmlgeneric.cc b/xmlgeneric.cc index 0d5a70c24..1aae5b6e7 100644 --- a/xmlgeneric.cc +++ b/xmlgeneric.cc @@ -19,37 +19,24 @@ */ -#include // for QByteArray -#include // for QHash -#include // for QIODevice, QIODevice::ReadOnly -#include // for QLatin1Char -#include -#include // for QStringView -#include // for QTextCodec -#include // for QXmlStreamAttributes -#include // for QXmlStreamReader, QXmlStreamReader::Characters, QXmlStreamReader::EndElement, QXmlStreamReader::IncludeChildElements, QXmlStreamReader::StartDocument, QXmlStreamReader::StartElement -#include // for qPrintable - -#include "defs.h" #include "xmlgeneric.h" -#include "src/core/file.h" // for File +#include // for as_const -enum xg_shortcut { - xg_shortcut_none = 0, - xg_shortcut_skip, - xg_shortcut_ignore -}; +#include // for QByteArray +#include // for QHash +#include // for QIODevice +#include // for QLatin1Char +#include // for QStringView +#include // for QTextCodec +#include // for QXmlStreamAttributes, QXmlStreamReader::Characters, QXmlStreamReader::EndElement, QXmlStreamReader::IncludeChildElements, QXmlStreamReader::StartDocument, QXmlStreamReader::StartElement +#include // for QXmlStreamReader +//#include // for QHash, QIODeviceBase::ReadOnly +#include // for qPrintable -static const QList* xg_tag_tbl; -static bool dynamic_tag_tbl; -static QHash* xg_shortcut_taglist; +#include "defs.h" // for fatal +#include "src/core/file.h" // for File -static QString rd_fname; -static QByteArray reader_data; -static const char* xg_encoding; -static QTextCodec* utf8_codec = QTextCodec::codecForName("UTF-8"); -static QTextCodec* codec = utf8_codec; // Qt has no vanilla ASCII encoding =( #define MYNAME "XML Reader" @@ -63,107 +50,60 @@ static QTextCodec* codec = utf8_codec; // Qt has no vanilla ASCII encoding =( * xml strains and insulates us from a lot of the grubbiness of expat. */ -static XgCallbackBase* -xml_tbl_lookup(const QString& tag, xg_cb_type cb_type) +XmlGenericReader::XgCallbackBase* +XmlGenericReader::xml_tbl_lookup(const QString& tag, xg_cb_type cb_type) { - for (const auto& tm : *xg_tag_tbl) { + for (const auto& tm : std::as_const(xg_tag_tbl)) { if (cb_type == tm.cb_type) { QRegularExpressionMatch match = tm.tag_re.match(tag); if (match.hasMatch()) { - return tm.tag_cb; + return tm.tag_cb.get(); } } } return nullptr; } -static void -xml_common_init(const QString& fname, const char* encoding, - const char* const* ignorelist, const char* const* skiplist) +void +XmlGenericReader::xml_common_init(const QString& fname, const char* encoding, + const char* const* ignorelist, const char* const* skiplist) { rd_fname = fname; - xg_encoding = encoding; - if (encoding) { - QTextCodec* tcodec = QTextCodec::codecForName(encoding); - if (tcodec) { - codec = tcodec; + if (encoding != nullptr) { + codec = QTextCodec::codecForName(encoding); + if (codec == nullptr) { + fatal(MYNAME " : codec \"%s\" is not available.\n", encoding); } + } else { + codec = QTextCodec::codecForName("UTF-8"); } - xg_shortcut_taglist = new QHash; + xg_shortcut_taglist.clear(); if (ignorelist != nullptr) { for (; ignorelist && *ignorelist; ++ignorelist) { - xg_shortcut_taglist->insert(QString::fromUtf8(*ignorelist), xg_shortcut_ignore); + xg_shortcut_taglist.insert(QString::fromUtf8(*ignorelist), xg_shortcut::sc_ignore); } } if (skiplist != nullptr) { for (; skiplist && *skiplist; ++skiplist) { - xg_shortcut_taglist->insert(QString::fromUtf8(*skiplist), xg_shortcut_skip); - } - } -} - -void -xml_init(const QString& fname, const QList* tbl, const char* encoding, - const char* const* ignorelist, const char* const* skiplist, bool dynamic_tbl) -{ - xg_tag_tbl = tbl; - dynamic_tag_tbl = dynamic_tbl; - - xml_common_init(fname, encoding, ignorelist, skiplist); -} - -void -xml_init(const QString& fname, const QList& tbl, const char* encoding, - const char* const* ignorelist, const char* const* skiplist) -{ - auto* tag_tbl = new QList; - dynamic_tag_tbl = true; - for (const auto& tm : tbl) { - auto* cb = new XgFunctionPtrCallback(tm.tag_cb); - QRegularExpression re(QRegularExpression::anchoredPattern(tm.tag_pattern)); - assert(re.isValid()); - tag_tbl->append({cb, tm.cb_type, re}); - } - xg_tag_tbl = tag_tbl; - - xml_common_init(fname, encoding, ignorelist, skiplist); -} - -void -xml_deinit() -{ - if (dynamic_tag_tbl) { - for (const auto& tm : *xg_tag_tbl) { - delete tm.tag_cb; + xg_shortcut_taglist.insert(QString::fromUtf8(*skiplist), xg_shortcut::sc_skip); } - delete xg_tag_tbl; } - xg_tag_tbl = nullptr; - - reader_data.clear(); - rd_fname.clear(); - - xg_encoding = nullptr; - codec = utf8_codec; - - delete xg_shortcut_taglist; - xg_shortcut_taglist = nullptr; } -static xg_shortcut -xml_shortcut(QStringView name) +XmlGenericReader::xg_shortcut +XmlGenericReader::xml_shortcut(QStringView name) { QString key = name.toString(); - if (xg_shortcut_taglist->contains(key)) { - return xg_shortcut_taglist->value(key); + if (xg_shortcut_taglist.contains(key)) { + return xg_shortcut_taglist.value(key); } - return xg_shortcut_none; + return xg_shortcut::sc_none; } -static void -xml_run_parser(QXmlStreamReader& reader) +void +XmlGenericReader::xml_run_parser(QXmlStreamReader& reader) { XgCallbackBase* cb; QString current_tag; @@ -184,10 +124,10 @@ xml_run_parser(QXmlStreamReader& reader) case QXmlStreamReader::StartElement: switch (xml_shortcut(reader.name())) { - case xg_shortcut_skip: + case xg_shortcut::sc_skip: reader.skipCurrentElement(); goto readnext; - case xg_shortcut_ignore: + case xg_shortcut::sc_ignore: goto readnext; default: break; @@ -196,13 +136,13 @@ xml_run_parser(QXmlStreamReader& reader) current_tag.append(QLatin1Char('/')); current_tag.append(reader.qualifiedName()); - cb = xml_tbl_lookup(current_tag, cb_start); + cb = xml_tbl_lookup(current_tag, xg_cb_type::cb_start); if (cb) { const QXmlStreamAttributes attrs = reader.attributes(); (*cb)(nullptr, &attrs); } - cb = xml_tbl_lookup(current_tag, cb_cdata); + cb = xml_tbl_lookup(current_tag, xg_cb_type::cb_cdata); if (cb) { QString c = reader.readElementText(QXmlStreamReader::IncludeChildElements); // readElementText advances the tokenType to QXmlStreamReader::EndElement, @@ -215,11 +155,11 @@ xml_run_parser(QXmlStreamReader& reader) break; case QXmlStreamReader::EndElement: - if (xml_shortcut(reader.name()) == xg_shortcut_skip) { + if (xml_shortcut(reader.name()) == xg_shortcut::sc_skip) { goto readnext; } - cb = xml_tbl_lookup(current_tag, cb_end); + cb = xml_tbl_lookup(current_tag, xg_cb_type::cb_end); if (cb) { (*cb)(reader.name().toString(), nullptr); } @@ -242,7 +182,7 @@ readnext: } } -void xml_read() +void XmlGenericReader::xml_read() { gpsbabel::File file(rd_fname); @@ -252,7 +192,7 @@ void xml_read() xml_run_parser(reader); if (reader.hasError()) { - fatal(MYNAME ":Read error: %s (%s, line %lld, col %lld)\n", + fatal(MYNAME " :Read error: %s (%s, line %lld, col %lld)\n", qPrintable(reader.errorString()), qPrintable(file.fileName()), reader.lineNumber(), @@ -262,14 +202,14 @@ void xml_read() // Chucks some bytes into the global QByteArray buffer and waits for // xml_readstring() to parse. -void xml_readprefixstring(const char* str) +void XmlGenericReader::xml_readprefixstring(const char* str) { reader_data.append(str); } // Parses a bytestream as if it were a file. Looks for an // for assert +#include // for make_shared, shared_ptr +#include // for QByteArray +#include // for QHash #include // for QList #include // for QRegularExpression #include // for QString +#include // for QStringView +#include // for QTextCodec #include // for QXmlStreamAttributes +#include // for QXmlStreamReader -// Maybe the XmlGeneric string callback really shouldn't have a type -// of its own; this was a crutch during the move from char* to QString. -// It's "just" a search and replace to make it go away, but it might -// be convenient to overload some day. -using xg_string = const QString&; - -enum xg_cb_type { - cb_start = 1, +enum class xg_cb_type { + cb_unknown = 0, + cb_start, cb_cdata, cb_end, }; -class XgCallbackBase -{ -public: - XgCallbackBase() = default; - virtual ~XgCallbackBase() = default; - XgCallbackBase(const XgCallbackBase&) = delete; - XgCallbackBase& operator=(const XgCallbackBase&) = delete; - XgCallbackBase(XgCallbackBase&&) = delete; - XgCallbackBase& operator=(XgCallbackBase&&) = delete; - - virtual void operator()(xg_string string, const QXmlStreamAttributes* attrs) const = 0; -}; - -template -class XgFunctor : public XgCallbackBase +/* + * xml_init will build and own a table of XgFunctor and/or + * XgFunctionPtrCallback entries from a list + * of non-static member functions and/or function pointers. + * + * QList> some_map = { + * {&SomeFormat::memberfn, cb_start, "/Placemark"}, + * {staticfn, cb_cdata, "/Placemark/coord"}, + * }; + * + * The this pointer from the Format instance must be passed if any + * of the callbacks are member functions, otherwise nullptr can be passed + * as this. + * + * xml_init(fname, this, some_map, encoding, ignorelist, skiplist); + * + */ +class XmlGenericReader { public: - using XgCb = void (XgFormat::*)(xg_string, const QXmlStreamAttributes*); - XgFunctor(XgFormat* obj, XgCb cb) : that_(obj), cb_(cb) {} - void operator()(xg_string string, const QXmlStreamAttributes* attrs) const override + /* Types */ + + // formats pass a list containing member function pointers and/or function pointers. + template + struct xg_fmt_map_entry { + // Constructor from a Member Function Pointer + using XgMfpCb = void (MyFormat::*)(const QString&, const QXmlStreamAttributes*); + xg_fmt_map_entry(XgMfpCb mfp, xg_cb_type ty, const char* tp) : tag_mfp_cb(mfp), cb_type(ty), tag_pattern(tp) {} + // Constructor from a Function Pointer. + using XgFpCb = void (const QString&, const QXmlStreamAttributes*); + xg_fmt_map_entry(XgFpCb fp, xg_cb_type ty, const char* tp) : tag_fp_cb(fp), cb_type(ty), tag_pattern(tp) {} + + /* Data Members */ + + XgMfpCb tag_mfp_cb{nullptr}; + XgFpCb* tag_fp_cb{nullptr}; + xg_cb_type cb_type{xg_cb_type::cb_unknown}; + const char* tag_pattern{nullptr}; + }; + + /* Member Functions */ + + template + void xml_init(const QString& fname, MyFormat* instance, const QList>& tbl, + const char* encoding = nullptr, + const char* const* ignorelist = nullptr, + const char* const* skiplist = nullptr) { - (that_->*cb_)(string, attrs); + build_xg_tag_map(instance, tbl); + + xml_common_init(fname, encoding, ignorelist, skiplist); } + void xml_read(); + void xml_readstring(const char* str); + void xml_readprefixstring(const char* str); + void xml_readunicode(const QString& str); + private: - XgFormat* that_; - XgCb cb_; -}; + /* Types */ -class XgFunctionPtrCallback : public XgCallbackBase -{ -public: - using XgCb = void (xg_string, const QXmlStreamAttributes*); - explicit XgFunctionPtrCallback(XgCb cb) : cb_(cb) {} - void operator()(xg_string string, const QXmlStreamAttributes* attrs) const override + class XgCallbackBase + { + public: + XgCallbackBase() = default; + virtual ~XgCallbackBase() = default; + XgCallbackBase(const XgCallbackBase&) = delete; + XgCallbackBase& operator=(const XgCallbackBase&) = delete; + XgCallbackBase(XgCallbackBase&&) = delete; + XgCallbackBase& operator=(XgCallbackBase&&) = delete; + + virtual void operator()(const QString& string, const QXmlStreamAttributes* attrs) const = 0; + }; + + template + class XgFunctor : public XgCallbackBase { - (*cb_)(string, attrs); + public: + using XgCb = void (XgFormat::*)(const QString&, const QXmlStreamAttributes*); + XgFunctor(XgFormat* obj, XgCb cb) : that_(obj), cb_(cb) {} + void operator()(const QString& string, const QXmlStreamAttributes* attrs) const override + { + (that_->*cb_)(string, attrs); + } + + private: + XgFormat* that_; + XgCb cb_; + }; + + class XgFunctionPtrCallback : public XgCallbackBase + { + public: + using XgCb = void (const QString&, const QXmlStreamAttributes*); + explicit XgFunctionPtrCallback(XgCb cb) : cb_(cb) {} + void operator()(const QString& string, const QXmlStreamAttributes* attrs) const override + { + (*cb_)(string, attrs); + } + + private: + XgCb* cb_; + }; + + // xml processing uses a list of xg_tag_map_entries. + struct xg_tag_map_entry { + std::shared_ptr tag_cb{nullptr}; + xg_cb_type cb_type{xg_cb_type::cb_unknown}; + QRegularExpression tag_re; + }; + + enum class xg_shortcut { + sc_none = 0, + sc_skip, + sc_ignore + }; + + /* Member Functions */ + + XgCallbackBase* xml_tbl_lookup(const QString& tag, xg_cb_type cb_type); + void xml_common_init(const QString& fname, const char* encoding, + const char* const* ignorelist, const char* const* skiplist); + xg_shortcut xml_shortcut(QStringView name); + void xml_run_parser(QXmlStreamReader& reader); + + // translate xg_fmt_map_entries to xg_tag_map_entries. + template + void build_xg_tag_map(MyFormat* instance, const QList>& map) + { + xg_tag_tbl.clear(); + for (const auto& entry : map) { + xg_tag_map_entry tme; + if (entry.tag_mfp_cb != nullptr) { + tme.tag_cb = std::make_shared>(instance, entry.tag_mfp_cb); + } else { + tme.tag_cb = std::make_shared(entry.tag_fp_cb); + } + QRegularExpression re(QRegularExpression::anchoredPattern(entry.tag_pattern)); + assert(re.isValid()); + tme.cb_type = entry.cb_type; + tme.tag_re = re; + xg_tag_tbl.append(tme); + } } -private: - XgCb* cb_; -}; + /* Data Members */ -// xml processing uses a QList. -// You may generated this yourself. See method 1 below. -// Or it may be generated for you using one of the subsequent -// methods. -struct xg_tag_map_entry { - XgCallbackBase* tag_cb; - xg_cb_type cb_type; - QRegularExpression tag_re; -}; + QList xg_tag_tbl; + QHash xg_shortcut_taglist; -// Table generation from an array containing function pointers. -// The above table can be generated by xml_init. See method 2 below. -// This is how things done historically before the Format class was -// introduced. -using xg_callback = void (xg_string, const QXmlStreamAttributes*); -struct xg_tag_mapping { - xg_callback* tag_cb; - xg_cb_type cb_type; - const char* tag_pattern; -}; + QString rd_fname; + QByteArray reader_data; + QTextCodec* codec{nullptr}; // Qt has no vanilla ASCII encoding =( -// Table generation from a list containing member function pointers. -// The above table can be generated by xml_init. See method 3 below. -template -struct xg_functor_map_entry { - using XgCb = void (MyFormat::*)(xg_string, const QXmlStreamAttributes*); - XgCb tag_cb; - xg_cb_type cb_type; - const char* tag_pattern; }; -template -QList* build_xg_tag_map(MyFormat* instance, const QList& map) -{ - auto* tag_tbl = new QList; - for (const auto& entry : map) { - auto* tag_cb = new XgFunctor(instance, entry.tag_cb); - QRegularExpression re(QRegularExpression::anchoredPattern(entry.tag_pattern)); - assert(re.isValid()); - tag_tbl->append({tag_cb, entry.cb_type, re}); - } - return tag_tbl; -} - -/* - * There are multiple ways to initialize with xml_init. - * - * 1. Build your own QList, and pass it. - * You own the table, you must do any required clean up. - * Your callbacks may be a mix of function pointers wrapped in XgFunctors - * and non-static member functions wrapped in XgFunctionPtrCallbacks. - * and XgFunctionPtrCallback(for static member functions or global functions) entries. - * xml_init(fname, tbl, encoding, ignorelist, skiplist, false); - * You must set the dynamic_tbl parameter to false so xml_deninit doesn't - * attempt to free the table resources when xml_deinit is called. - * - * 2. Have xml_init build and own a table of XgFunctionPtrCallback entries - * from an list of function pointers, i.e. a QList of xg_tag_mapping elements. - * This only works when all callbacks are function pointers. - * xml_init(fname, tbl, encoding, ignorelist, skiplist); - * Generated table entries will automatically be freed. - * - * 3. Have xml_init build and own a table of XgFunctor entries from a list - * of non-static member functions, i.e. a QList. - * This only works when all callbacks are non-static member functions. - * xml_init(fname, build_xg_tag_map(instance, map), encoding, ignorelist, skiplist, true); - * You must set the dynamic_tbl parameter to true to free the generated table - * resources when xml_deinit is called. - * - */ -void xml_init(const QString& fname, const QList* tbl, const char* encoding, - const char* const* ignorelist = nullptr, - const char* const* skiplist = nullptr, bool dynamic_tbl = false); -void xml_init(const QString& fname, const QList& tbl,const char* encoding, - const char* const* ignorelist = nullptr, - const char* const* skiplist = nullptr); -void xml_read(); -void xml_readstring(const char* str); -void xml_readprefixstring(const char* str); -void xml_readunicode(const QString& str); -void xml_deinit(); - #endif // XMLGENERIC_H_INCLUDED_ -- 2.30.2